#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义允许的命令列表
const char *allowed_commands[] = { 
    "cp",
    "ls",
    "ln",
    "dd",
    "mv",
    "rm",
    "cat",
    "tar",
    "sed",
    "curl",
    "find",
    "mkdir",
    "grep",
    "file",
    "echo",
    "zstd",
    "touch",
    "chmod",
    NULL
};

char *get_command_basename(const char *input_command) {
    if (input_command == NULL || *input_command == '\0') {
        // 输入为空或空字符串
        return NULL;
    }

    const char *last_slash = strrchr(input_command, '/');
    
    if (last_slash == NULL) {
        // 没有找到斜杠，返回整个字符串
        return strdup(input_command);
    } else {
        // 找到了斜杠，返回斜杠后面的部分
        return strdup(last_slash + 1);
    }
}

int is_command_allowed(const char *input_command) {
    char *command = get_command_basename(input_command);

    if (command != NULL) {
        for (int i = 0; allowed_commands[i] != NULL; i++) {
            if (strcmp(command, allowed_commands[i]) == 0) {
                return 1;
            }
        }
    } else {
        printf("command is empty.\n");
    }

    return 0;
}

char **create_allowed_paths() {
    // initial allowed paths
    const char *initial_allowed_paths[] = { 
        "/opt/epkg", 
        "/etc/resolv.conf",
        "/etc/pki/ca-trust",
        NULL
    };

    // $HOME
    const char *home = getenv("HOME");
    if (home == NULL) {
        fprintf(stderr, "HOME environment variable not set\n");
        exit(EXIT_FAILURE);
    }
    char *home_path = strdup(home);
    // size_t len = strlen(home) + sizeof("/.epkg") - 1;
    // char *home_epkg_path = malloc(len + 1); // +1 for the null terminator
    // if (home_epkg_path == NULL) {
    //     fprintf(stderr, "Failed to allocate memory for home_epkg_path\n");
    //     exit(EXIT_FAILURE);
    // }
    // snprintf(home_epkg_path, len + 1, "%s/.epkg", home);

    // initial_allowed_paths
    size_t initial_count = 0;
    while (initial_allowed_paths[initial_count] != NULL) {
        initial_count++;
    }

    // allowed_paths
    char **allowed_paths = malloc((initial_count + 2) * sizeof(char *));
    if (allowed_paths == NULL) {
        free(home_path);
        fprintf(stderr, "Failed to allocate memory for allowed_paths\n");
        exit(EXIT_FAILURE);
    }

    for (size_t i = 0; i < initial_count; i++) {
        allowed_paths[i] = strdup(initial_allowed_paths[i]);
        if (allowed_paths[i] == NULL) {
            for (size_t j = 0; j < i; j++) {
                free(allowed_paths[j]);
            }
            free(home_path);
            free(allowed_paths);
            fprintf(stderr, "Failed to duplicate initial path %zu\n", i);
            exit(EXIT_FAILURE);
        }
    }
    allowed_paths[initial_count] = home_path;
    allowed_paths[initial_count + 1] = NULL;

    return allowed_paths;
}

// 判断str是否以prefix开头
int starts_with(const char *str, const char *prefix) {
    size_t prefix_len = strlen(prefix);
    return strncmp(str, prefix, prefix_len) == 0 && (str[prefix_len] == '/' || str[prefix_len] == '\0');
}

// 检查给定路径是否在白名单中
int is_path_allowed(const char *path, const char *allowed_paths[]) {
    if (path != NULL) {
        for (int i = 0; allowed_paths[i] != NULL; i++) {
            if (starts_with(path, allowed_paths[i])) {
                return 1;
            }
        }
    } else {
        printf("path is empty. Please use abs path.\n");
    }
    return 0;   
}

int check_command_path(char *const argv[]) {
    char **allowed_paths = create_allowed_paths();

    for (int i = 1; argv[i] != NULL; ++i) {
        if (argv[i][0] == '/') {
            if (!is_path_allowed(argv[i], allowed_paths)) {
                printf("path %s is not allowed.\n", argv[i]);
                return 0;
            }
        }
    }

    return 1; 
}